package net.xo68.coordinator.core.gid;

import com.alipay.sofa.jraft.Node;
import com.alipay.sofa.jraft.RaftGroupService;
import com.alipay.sofa.jraft.conf.Configuration;
import com.alipay.sofa.jraft.entity.PeerId;
import com.alipay.sofa.jraft.option.NodeOptions;
import com.alipay.sofa.jraft.rpc.RaftRpcServerFactory;
import com.alipay.sofa.jraft.rpc.RpcServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;

/**
 * 全局编号服务
 * @author wuxie
 * @version 2020-9-28
 */
@Slf4j
public class GidServer {

    // jraft 服务端服务框架
    private RaftGroupService raftGroupService;
    // raft 节点
    private Node node;
    // 业务状态机
    private GidStateMachine fsm;

    private final GidProperties gidProperties;
    private final NodeOptions nodeOptions;

    public GidServer(GidProperties gidProperties) {
        this.gidProperties = gidProperties;
        this.nodeOptions=new NodeOptions();
    }

    public void start()throws IOException {
        PeerId serverId = new PeerId();
        if (!serverId.parse(gidProperties.getServerAddress())) {
            throw new IllegalArgumentException("Fail to parse serverId:" + gidProperties.getServerAddress());
        }

        String dataPath=gidProperties.getDataPath();
        FileUtils.forceMkdir(new File(dataPath));

        RpcServer rpcServer = RaftRpcServerFactory.createRaftRpcServer(serverId.getEndpoint());
        // 注册业务处理器
        rpcServer.registerProcessor(new NewIdProcessor(this));


        nodeOptions.setElectionTimeoutMs(gidProperties.getElectionTimeout());
        nodeOptions.setDisableCli(gidProperties.isDisableCli());
        nodeOptions.setSnapshotIntervalSecs(gidProperties.getSnapshotIntervalSecs());

        Configuration initConf = new Configuration();
        if (!initConf.parse(gidProperties.getClusterAddress())) {
            throw new IllegalArgumentException("Fail to parse initConf:" + gidProperties.getClusterAddress());
        }
        // 设置初始集群配置
        nodeOptions.setInitialConf(initConf);

         // 初始化状态机
        this.fsm=new GidStateMachine();
        // 设置状态机到启动参数
        nodeOptions.setFsm(fsm);
        // 设置存储路径
        // 日志, 必须
        nodeOptions.setLogUri(dataPath + File.separator + "log");
        // 元信息, 必须
        nodeOptions.setRaftMetaUri(dataPath + File.separator + "raft_meta");
        // snapshot, 可选, 一般都推荐
        nodeOptions.setSnapshotUri(dataPath + File.separator + "snapshot");
        // 初始化 raft group 服务框架
        this.raftGroupService = new RaftGroupService(gidProperties.getGroupId(), serverId, nodeOptions, rpcServer);
        // 启动
        this.node = this.raftGroupService.start();

    }

    public RaftGroupService getRaftGroupService() {
        return raftGroupService;
    }

    public Node getNode() {
        return node;
    }

    public GidStateMachine getFsm() {
        return fsm;
    }

    /**
     * 生成重定向请求
     */
    public NewIdResponse redirect() {
        NewIdResponse response = new NewIdResponse();
        response.setStatus(false);
        if (node != null) {
            PeerId leader = node.getLeaderId();
            if (leader != null) {
                response.setRedirect(leader.toString());
            }
        }

        return response;
    }
}
